﻿using System;
using System.Collections.Generic;
using System.Reflection;
using Z.BulkOperations;
using Z.Dapper.Plus;

namespace Dapper.Sharding
{
    public class ShardingFactory
    {
        static ShardingFactory()
        {
            SetBatchSize(100);
        }

        public static void SetBatchSize(int size)
        {
            DapperPlusManager.MapperFactory = map => map.BatchSize(size);
        }

        /// <summary>
        /// 是否缓存sql
        /// </summary>
        /// <param name="cached"></param>
        public static void CacheSql(bool cached)
        {
            DapperFactory.CacheSql = cached;
        }

        public static bool ClickHouseFixedString { get; set; } = false;

        public static void SetSnowFlakeWorker(long workerId, long datacenterId, long seqLength = 0)
        {
            SnowflakeId.worker = new IdWorker(workerId, datacenterId, seqLength);
        }

        public static void SetLongIdWorker(ushort workerId = 0, byte workLength = 6, byte seqLength = 6)
        {
            //https://gitee.com/yitter/idgenerator
            //https://github.com/yitter/IdGenerator
            var opt = new IdGeneratorOptions();
            if (workLength != 6)
            {
                opt.WorkerIdBitLength = workLength; //默认值6，取值范围 [1, 15]（要求：序列数位长+机器码位长不超过22）
            }
            if (workerId != 0) //当workLength等于6,workerId最大值63
            {
                opt.WorkerId = workerId; //最大值 2 ^ WorkerIdBitLength - 1
            }
            if (seqLength != 6) //默认6支持10万并发,10才能支持50-200万并发,取值范围[3,21]
            {
                opt.SeqBitLength = seqLength;
            }
            IdHelper.IdGenInstance = new DefaultIdGenerator(opt);
        }

        public static IClient CreateClient(DataBaseType dbType, DataBaseConfig config, DataBaseVersion version = DataBaseVersion.Default)
        {
            switch (dbType)
            {
                case DataBaseType.MySql:
                    return new MySqlClient(config);
                case DataBaseType.SqlServer:
                    {
                        if (version == DataBaseVersion.Default)
                        {
                            version = DataBaseVersion.SqlServer2008;
                        }
                        return new SqlServerClient(config, version);
                    }
                case DataBaseType.Sqlite:
                    return new SQLiteClient(config);
                case DataBaseType.Postgresql:
                    return new PostgreClient(config);
                case DataBaseType.Oracle:
                    return new OracleClient(config);
            }
            return null;
        }

        public static IClient CreateClient(ClientConfig config)
        {
            var client = CreateClient(config.DbType, config.Config, config.DbVersion);
            client.AutoCreateDatabase = config.AutoCreateDatabase;
            client.AutoCreateTable = config.AutoCreateTable;
            client.AutoCompareTableColumn = config.AutoCompareTableColumn;
            client.AutoCompareTableColumnLength = config.AutoCompareTableColumnLength;
            client.AutoCompareTableColumnDelete = config.AutoCompareTableColumnDelete;
            client.Id = config.Id;
            client.Database = config.Database;
            client.DatabaseList = config.DatabaseList;
            return client;
        }

        public static IClient CreateClient(string jsonFile, string key = null)
        {
            var config = ConfigJsonNet.LoadConfig(jsonFile, key);
            return CreateClient(config);
        }

        public static List<IClient> CreateClientList(string jsonFile, string key = null)
        {
            var configList = ConfigJsonNet.LoadConfigList(jsonFile, key);
            var list = new List<IClient>();
            foreach (var item in configList)
            {
                list.Add(CreateClient(item));
            }
            return list;
        }

        public static Dictionary<string, IClient> CreateClientDict(string jsonFile, string key = null)
        {
            var configList = ConfigJsonNet.LoadConfigList(jsonFile, key);
            var dict = new Dictionary<string, IClient>();
            foreach (var item in configList)
            {
                dict.Add(item.Id, CreateClient(item));
            }
            return dict;
        }

        public static void AddJsonType(Type type)
        {
            TypeHandlerJsonNet.Add(type);
        }

        public static void AddJsonType(Assembly assembly)
        {
            TypeHandlerJsonNet.Add(assembly);
        }

        public static DistributedTransaction CreateDistributedTransaction()
        {
            return new DistributedTransaction();
        }

        public static ReadWirteClient CreateReadWriteClient(IClient writeClient, params IClient[] readClientList)
        {
            return new ReadWirteClient(writeClient, readClientList);
        }

        public static string NextObjectId()
        {
            return ObjectId.GenerateNewIdAsString();
        }

        public static DateTime ObjectIdTime(string id)
        {
            return new ObjectId(id).CreationTime;
        }

        public static int ObjectIdTimestamp(string id)
        {
            return new ObjectId(id).Timestamp;
        }

        public static long NextSnowId()
        {
            return SnowflakeId.GenerateNewId();
        }

        public static string NextSnowIdAsString()
        {
            return NextSnowId().ToString();
        }

        public static long NextLongId()
        {
            return IdHelper.IdGenInstance.NewLong();
        }

        public static string NextLongIdAsString()
        {
            return NextLongId().ToString();
        }

        public static void AddTypeHandler(Type type, SqlMapper.ITypeHandler handler, IBulkValueConverter handlerz)
        {
            TypeHandlerCache.Add(type, () =>
            {
                SqlMapper.AddTypeHandler(type, handler);
                DapperPlusManager.AddValueConverter(type, handlerz);
            });
        }
    }
}
